#include <iostream>
#include <mutex>
#include <pthread.h>
#define NUM_THREADS 5 // 线程个数

// 普通懒汉式实现--线程不安全
class SingleInstance {
    public:
    // 获取单例对象
    static SingleInstance* GetInstance();

    // 释放单例，进程退出时调用
    static void deleteInstance();

    // 打印单例地址
    void Print();
    private:
    // 将其构造和析构函数成为私有的，禁止外部构造和析构
    SingleInstance();
    ~SingleInstance();

    //将其拷贝构造和复制构造成为私有函数，禁止外部拷贝和赋值
    SingleInstance(const SingleInstance &signal);
    const SingleInstance &operator=(const SingleInstance &signal);

    private:
    // 唯一单例对象指针
    static SingleInstance* m_SingleInstance_;
};

// 初始化静态成员变量
SingleInstance* SingleInstance::m_SingleInstance_ = nullptr;

SingleInstance* SingleInstance::GetInstance() {
    if(m_SingleInstance_ == nullptr) {
        m_SingleInstance_ = new (std::nothrow) SingleInstance;  // 没有加锁是线程不安全的，当线程并发时会创建多个实例
    }
    return m_SingleInstance_;
}

void SingleInstance::deleteInstance() {
    if(m_SingleInstance_) {
        delete m_SingleInstance_;
        m_SingleInstance_ = nullptr;
    }
}

void SingleInstance::Print() {
    std::cout << "我的实例内存地址是： " << this << std::endl;
}

SingleInstance::SingleInstance() {
    std::cout << "构造函数" << std::endl;
}

SingleInstance::~SingleInstance() {
    std::cout << "析构函数" << std::endl;
}

// 线程函数
void* PrintHello(void* threadid) {
    // 主线程与子线程分离，两者相互不干涉，子线程结束同时子线程的资源自动回收
    pthread_detach(pthread_self());

    // 对传入的参数进行强制类型转换，由无类型指针变为整数型指针，然后再读取
    int tid = *((int*)threadid);

    std::cout << "Hi,我是线程 ID:[" << tid << "]" << std::endl;

    // 打印实例地址
    SingleInstance::GetInstance()->Print();

    pthread_exit(nullptr);
}


int main () {
    std::cout << "hello 普通懒汉式单例模式!!!" << std::endl;
    pthread_t threads[NUM_THREADS] = {0};
    int indexes[NUM_THREADS] = {0};

    int ret = 0;
    int i = 0;

    std::cout << "main() : 开始 ... " << std::endl;

    for(i = 0;i < NUM_THREADS;i++) {
        std::cout << "main() : 创建线程：[" << i << "]" << std::endl;

        indexes[i] = i;  // 先保存i的值

        // 传入的时候必须强制转换为void*类型，及无类型指针
        ret = pthread_create(&threads[i],NULL,PrintHello,(void*)&(indexes[i]));

        if(ret) {
            std::cout << "Error:无法创建线程，" << ret << std::endl;
            exit(-1);
        }
    }

    // 手动释放单实例的资源
    SingleInstance::deleteInstance();
    std::cout << "main() : 结束！" << std::endl;

    return 0;
}